package cn.intellijboy.gradle.plugin;

import cn.intellijboy.gradle.plugin.extension.GradleSettingExtension;
import cn.intellijboy.gradle.plugin.task.AnalyzeConfigurationTask;
import cn.intellijboy.gradle.plugin.task.AnalyzeDependencyTask;
import cn.intellijboy.gradle.plugin.task.DownloadDependencyTask;
import org.gradle.api.JavaVersion;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.testing.Test;
import org.gradle.jvm.toolchain.JavaLanguageVersion;
import org.gradle.plugins.ide.idea.model.IdeaModel;

import java.util.ArrayList;
import java.util.List;

/**
 * 约定式插件，适用于单体与多模块工程：
 * - 应用 java-library 与 idea 插件
 * - IDEA 下载源码与Javadoc
 * - 配置 compileOnly/testCompileOnly/testAnnotationProcessor 继承链
 * - Java Toolchain = 17，源/目标兼容性 17
 * - Java 编译参数：UTF-8、-parameters、deprecation
 * - 测试平台：JUnit Platform
 */
public class GradleCommonBuildPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        // 扩展：允许用户在 settings 或项目中配置
        initDefaultExtion(project);
        // 自动配置当前项目
        configProject(project);
    }

    private void configProject(Project project) {
        // 在根工程应用：
        if (project.getRootProject() == project) {
            if (project.getSubprojects().isEmpty()) {
                // - 若存在子工程，仅对子工程生效；
                configureProject(project);
            } else {
                // - 若无子工程（单模块工程），则对当前工程生效。
                project.getSubprojects().forEach(this::configureProject);
            }
        } else {
            // 在子工程应用：仅对该子工程生效。
            configureProject(project);
        }
    }

    private void initDefaultExtion(Project project) {
        GradleSettingExtension ext = project.getExtensions()
                .create("springAi", GradleSettingExtension.class);
        setDefaultsIfAbsent(ext);
    }

    private void configureProject(Project project) {
        // 基础插件
        project.getPlugins().apply("java-library");
        project.getPlugins().apply("idea");

        // 读取/创建扩展并设定默认值
        GradleSettingExtension ext = project.getExtensions().findByType(GradleSettingExtension.class);
        if (ext == null) {
            ext = project.getExtensions().create("springAi", GradleSettingExtension.class);
        }
        setDefaultsIfAbsent(ext);

        // 统一仓库镜像配置（单体工程对当前工程生效；多模块工程对子模块生效）
        project.getRepositories().mavenLocal();
        java.util.List<String> repos = (ext.getMavenRepositories() != null && ext.getMavenRepositories().isPresent())
                ? ext.getMavenRepositories().get()
                : defaultMavenRepos();
        for (String url : repos) {
            if (url != null && !url.isEmpty()) {
                project.getRepositories().maven(repo -> configMavenRepos(repo, url, url));
            }
        }
        project.getRepositories().mavenCentral();

        // IDEA 源码与Javadoc下载
        project.getExtensions().configure(IdeaModel.class, idea -> {
            idea.getModule().setDownloadJavadoc(Boolean.TRUE.equals(project.findProperty("springAi.downloadIdeaJavadoc")) ||
                    Boolean.TRUE.equals(project.findProperty("springAi.downloadIdeaJavadoc")));
            idea.getModule().setDownloadSources(Boolean.TRUE.equals(project.findProperty("springAi.downloadIdeaSources")) ||
                    Boolean.TRUE.equals(project.findProperty("springAi.downloadIdeaSources")));
        });

        // 当 Java 插件存在时，配置 Toolchain 与编译参数
        GradleSettingExtension finalExt = ext;
        project.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
            // Toolchain & 兼容性
            JavaPluginExtension java = project.getExtensions().getByType(JavaPluginExtension.class);
            int lang = orDefault(finalExt.getJavaLanguageVersion(), 21);
            JavaVersion jv = (lang >= 21) ? JavaVersion.VERSION_21 : (JavaVersion.VERSION_17);
            java.setSourceCompatibility(jv);
            java.setTargetCompatibility(jv);
            java.getToolchain().getLanguageVersion().set(JavaLanguageVersion.of(lang));

            // 编译任务统一参数
            project.getTasks().withType(JavaCompile.class).configureEach(jc -> {
                jc.getOptions().setEncoding("UTF-8");
                jc.getOptions().setDeprecation(true);
                List<String> args = new ArrayList<>(jc.getOptions().getCompilerArgs());
                if (!args.contains("-parameters")) {
                    args.add("-parameters");
                }
                jc.getOptions().setCompilerArgs(args);
            });
        });

        // 测试平台
        project.getTasks().withType(Test.class).configureEach(Test::useJUnitPlatform);

        // 注册自定义任务
        registerDependencyTask(project);

        // 配置继承关系（在 java 插件应用后这些配置将可用；若不存在则以 maybeCreate 兜底）
        Configuration annotationProcessor = findOrCreate(project, "annotationProcessor");
        Configuration testAnnotationProcessor = findOrCreate(project, "testAnnotationProcessor");
        Configuration compileOnly = findOrCreate(project, "compileOnly");
        Configuration testCompileOnly = findOrCreate(project, "testCompileOnly");

        if (annotationProcessor != null && compileOnly != null) {
            compileOnly.extendsFrom(annotationProcessor);
        }
        if (testAnnotationProcessor != null && annotationProcessor != null) {
            testAnnotationProcessor.extendsFrom(annotationProcessor);
        }
        if (testCompileOnly != null) {
            if (testAnnotationProcessor != null) {
                testCompileOnly.extendsFrom(testAnnotationProcessor);
            }
            if (compileOnly != null) {
                testCompileOnly.extendsFrom(compileOnly);
            }
        }
    }

    private void configMavenRepos(MavenArtifactRepository repo, String name, String url) {
        repo.setName(name);
        repo.setUrl(url);
    }

    private int orDefault(org.gradle.api.provider.Property<Integer> prop, int defaultValue) {
        if (prop != null && prop.isPresent()) {
            Integer v = prop.get();
            if (v != null) return v;
        }
        return defaultValue;
    }

    private void setDefaultsIfAbsent(GradleSettingExtension ext) {
        if (!ext.getDownloadIdeaSources().isPresent()) {
            ext.getDownloadIdeaSources().set(true);
        }
        if (!ext.getDownloadIdeaJavadoc().isPresent()) {
            ext.getDownloadIdeaJavadoc().set(false);
        }
        if (!ext.getJavaLanguageVersion().isPresent()) {
            ext.getJavaLanguageVersion().set(21);
        }
        if (ext.getMavenRepositories() != null && !ext.getMavenRepositories().isPresent()) {
            ext.getMavenRepositories().set(defaultMavenRepos());
        }
    }

    private java.util.List<String> defaultMavenRepos() {
        java.util.List<String> list = new java.util.ArrayList<>();
        list.add("https://maven.aliyun.com/repository/public/");
        list.add("https://repo.huaweicloud.com/repository/maven/");
        list.add("https://mirrors.cloud.tencent.com/nexus/repository/maven-public/");
        return list;
    }

    private Configuration findOrCreate(Project project, String name) {
        try {
            return project.getConfigurations().getByName(name);
        } catch (Exception ignored) {
            // 在尚未创建时兜底创建，避免多插件应用顺序问题
            return project.getConfigurations().maybeCreate(name);
        }
    }

    /**
     * 注册自定义任务
     */
    private void registerDependencyTask(Project project) {
        // 1. 配置解析任务
        project.getTasks()
                .register("analyzeConfiguration", AnalyzeConfigurationTask.class, task -> {
                    task.setGroup("xingzhe");
                    task.setDescription("获取所有或指定的配置对象");
                });

        // 2. 依赖解析任务
        TaskProvider<AnalyzeDependencyTask> analyzeDependencyTask = project.getTasks()
                .register("analyzeDependency", AnalyzeDependencyTask.class, task -> {
                    task.setGroup("xingzhe");
                    task.setDescription("获取在线、项目、本地依赖，并且可以指定获取所有或指定的依赖对象，支持获取一层或整棵依赖树");
                });

        // 3. 依赖下载任务 - 依赖 analyzeDependency
        project.getTasks()
                .register("downloadDependency", DownloadDependencyTask.class, task -> {
                    task.setGroup("xingzhe");
                    task.setDescription("下载指定依赖或指定下载某个配置对象下的依赖、支持指定依赖输出内容格式和保存位置");
                    task.dependsOn(analyzeDependencyTask);
                });
    }
}

